package middleware

import (
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"fmt"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"net/http"
	"peilian-api/app/global/databases/tables"
	"peilian-api/app/global/variable"
	"peilian-api/utils/format"
	"peilian-api/utils/tools"
	"time"
)

type AppIdDateSig struct {
	AppId     string `header:"X-Client-Id"`
	Date      string `header:"X-Date"`
	Signature string `header:"X-Signa"`
}

func AppVerify() gin.HandlerFunc {
	return func(c *gin.Context) {
		var appIdDateSig AppIdDateSig
		if err := c.ShouldBindHeader(&appIdDateSig); err != nil {
			format.NewResponseJson(c).Err(http.StatusUnauthorized, err.Error())
			return
		}
		var agent tables.Agent
		filter := &tables.Agent{AppId: appIdDateSig.AppId}
		if err := variable.DB.MySQL.Select("AppSecret", "ID").
			Preload("FirstConstitute", func(tx *gorm.DB) *gorm.DB {
				return tx.Select("Name", "Type", "AgentID")
			}).First(&agent, filter).Error; err != nil {
			format.NewResponseJson(c).Err(http.StatusUnauthorized, "app验证失败")
			return
		}
		sig := Sign(appIdDateSig.AppId, agent.AppSecret, appIdDateSig.Date)
		if sig != appIdDateSig.Signature {
			format.NewResponseJson(c).Err(http.StatusUnauthorized, "app验证失败")
			return
		}
		t, err := tools.ParseUTC8Str(appIdDateSig.Date)
		if err != nil {
			format.NewResponseJson(c).Err(http.StatusUnauthorized, "时间格式有误")
			return
		}
		now := time.Now()
		beforeNow := now.Add(-15 * time.Minute)
		afterNow := now.Add(15 * time.Minute)
		if t.Before(beforeNow) || t.After(afterNow) {
			format.NewResponseJson(c).Err(http.StatusUnauthorized, "请按照当前时间重新生成signa值")
			return
		}
		c.Set("agentName", agent.FirstConstitute.Name)
		c.Set("agentType", agent.FirstConstitute.Type)
		c.Next()
	}
}

func Sign(appId, sec, dateStr string) string {
	str := fmt.Sprintf("%s%s", appId, dateStr)
	h := md5.New()
	h.Write([]byte(str))
	hex := fmt.Sprintf("%x", h.Sum(nil))
	fmt.Println("md5: ", hex)
	mac := hmac.New(sha1.New, []byte(sec))
	mac.Write([]byte(hex))
	return fmt.Sprintf("%x", mac.Sum(nil))
}
